﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace MoqContrib.AutoMock.All.Tests.TheContainer
{
    [TestFixture]
    public abstract class WhenBuildingObjectGraph<T>
        where T : IDoContainerStuff, IAutoMockContainer, new()
    {

        #region Types used for testing
        public interface IService1 { }
        public interface IService2 { }
        public interface IService3 { }
        public class DependsOn2 : IService1
        {
            public DependsOn2(IService2 s) { Dependancy = s; }
            public IService2 Dependancy { get; set; }
        }
        public class Root
        {
            public Root(IService1 s, IService3 s3) { Dependancy1 = s; Dependancy3 = s3; }
            public IService1 Dependancy1 { get; set; }
            public IService3 Dependancy3 { get; set; }
        }
        public class Service2 : IService2 { }
        public class Service1 : IService2 { }
        #endregion

        [Test]
        public void I_can_mock_simple_dependencies()
        {
			using (var container = new T())
			{
				var result = container.CreateTestSubject<DependsOn2>();
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Dependancy, Is.SameAs(container.Mock.Get<IService2>().Object));
			}
        }

        [Test]
        public void I_can_resolve_simple_dependencies()
        {
			using (var container = new T())
			{
				container.RegisterServiceAs<IService2, Service2>();
				var result = container.CreateTestSubject<DependsOn2>();
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Dependancy.GetType(), Is.SameAs(typeof(Service2)));
			}
        }

        [Test]
        public void I_can_resolve_deep_object_graphs()
        {
			using (var container = new T())
			{
				container.RegisterServiceAs<IService2, Service2>();
				container.RegisterServiceAs<IService1, DependsOn2>();

				var result = container.CreateTestSubject<Root>();

				Assert.That(result, Is.Not.Null);
				Assert.That(result.Dependancy1, Is.InstanceOf<DependsOn2>());
				Assert.That(((DependsOn2)result.Dependancy1).Dependancy, Is.InstanceOf<Service2>());
				Assert.That(result.Dependancy3, Is.SameAs(container.Mock.Get<IService3>().Object));
			}
        }

		[Test]
		public void I_can_resolve_a_class_with_no_dependencies()
		{
			using (var container = new T())
			{
				var result = container.CreateTestSubject<Service1>();
				Assert.That(result, Is.Not.Null);
				
			}
		}

		[Test]
		public void I_can_resolve_something_I_explicitly_registered()
		{
			using (var container = new T())
			{
				container.RegisterService<Service1>();
				var result = container.CreateTestSubject<Service1>();
				Assert.That(result, Is.Not.Null);
			}
		}

		/// <summary>
		/// An issue with Castle makes this an issue. You would blanket register a bunch
		/// of types, but when you go to create the test subject it fails because it won't
		/// admit that it already has the component
		/// </summary>
		[Test]
		public void I_can_resolve_something_I_already_registered_its_interface()
		{
			using (var container = new T())
			{
				container.RegisterServiceAs<IService2, Service2>();
				var result = container.CreateTestSubject<Service2>();
				Assert.That(result, Is.Not.Null);
			}
		}
    }
}
